// File: WebPageSearcher.hpp
//
// Created by 唐建 on 2023/12/2.
//

#ifndef CPP_REMOTE_UBUNTU_WEBPAGESEARCHER_H
#define CPP_REMOTE_UBUNTU_WEBPAGESEARCHER_H

#include "../json/json.hpp"
#include "ProtocolParser.h"
#include "TcpConnection.h"
#include <cerrno>
#include <string>
#include <memory>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>

class TcpCoonection;

class WebPage;

class WebPageResp;

using WebPageVector = std::vector<WebPage>;
using PageOffsetMap = std::map<int, std::pair<int, int >>; // pageId (begin end)
using InvertIndexMap = std::unordered_map<std::string, std::set<std::pair<int, double>>>; // word-set((),(), ...)

using CutWordsAndFreq = std::vector<std::pair<string,double>>;
using QueryWordsVector = std::vector<std::string>;
using WordWeightVector = std::vector<double>;
using DocIdWordWeightPair = std::pair<int, WordWeightVector>;
using DocIdWordWeightVector = std::vector<DocIdWordWeightPair>; // docId ((word, w'), (), ...)

using WebPageRespP = std::unique_ptr<WebPageResp>;
using WebPageRespPVector = std::unique_ptr<std::vector<WebPageResp>>;
class TcpConnection;

using TcpConnectionPtr = std::shared_ptr<TcpConnection>;

struct WebPageResp {
    int docId;
    std::string &docTitle;
    std::string &url;
    std::string docSummary;

    WebPageResp(int docId, std::string &docTitle, std::string &url, std::string docSummary);
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(WebPageResp, docId, docTitle, url, docSummary);

struct WebPage {
    int _docId;
    std::string _title;
    std::string _link;
    std::string _content;

    WebPage(int id, const std::string &title, const std::string &link, const std::string &content);

    WebPage(WebPage &&other) noexcept;

    WebPage &operator=(WebPage &&other) noexcept;

    std::string getSummary(const QueryWordsVector &queryWords);

    std::string getSummaryByDP(std::string searchStr);

    WebPageRespP getWebPage2Resp(const QueryWordsVector &queryWords);
};

class WebpageQuery {
private:
    WebPageVector _pages;
    PageOffsetMap _offsetLib;
    InvertIndexMap _invertIndexLib;

    static WebpageQuery *_pWebpageQuery;
    static pthread_once_t _pOnceWebQ;

public:
    static WebpageQuery *getInstance();

    std::string doQueryW(std::string sought, int pageSize, int pageNum);

private:
    explicit WebpageQuery();

    ~WebpageQuery() = default;

    static void WebpageQueryInit();

    static void destroy();

    void loadLibrary(std::string &dbpath);

    void loadPageLib(std::string &dbpath);

    void loadIndexLib(std::string &dbpath);

    void loadOffsetLib(std::string &dbpath);

    std::string returnNoAnswer();

    WordWeightVector getQueryWordsWeightVector(QueryWordsVector &queryWords);

    bool executeQuery(const CutWordsAndFreq &queryWords, DocIdWordWeightVector &matchVector);

    WebPageRespPVector getWebPagesRespPVector(DocIdWordWeightVector &matchDoc, CutWordsAndFreq &queryWords,
                                              int offset, int num, std::string &sought);

};

class WebPageSearcher {
private:
    std::string _sought; // 搜索词汇
    TcpConnectionPtr _coon; // 客户端连接

public:
    //WebPageSearcher(WebPageSearcher &searcher);

    // 搜索的内容 客户端连接
    WebPageSearcher(std::string sought, TcpConnectionPtr coon);

    // 执行搜索的入口
    std::string doQuery();
};

#endif //CPP_REMOTE_UBUNTU_WEBPAGESEARCHER_H
